<?php

declare(strict_types=1);

namespace app\service\system\file;

use app\model\system\ResourceModel;
use owns\enum\FileEnum;
use owns\enum\AppEnum;
use think\facade\Config;

/**
 * 文件管理
 */
class FileManage
{
    public readonly string $default;

    public readonly array $disks;

    public readonly array $file;

    public readonly string $domain;

    private string $dirtype;

    public function __construct($default = '')
    {
        $config = Config::get('filesystem');
        $this->default = $default ?: $config['default'];
        $this->disks = $config['disks'];
        $this->file = $config['file'];
        $this->domain = $this->disks[$this->default]['domain'] ?? '';
    }
    /**
     * 最大可上传文件
     */
    public function maxSize($size = true)
    {
        if ($size) {
            return $this->file['maxSize'] * FileEnum::MB;
        }
        return $this->file['maxSize'] . 'MB';
    }
    /**
     * 上传
     * @param File $file
     * @param string $dirtype
     */
    public function upload($file, string $dirtype): array
    {
        $suffix = strtolower(strstr($file->getOriginalName(), '.'));
        if (!in_array($suffix, explode(',', $this->file['suffix']))) {
            tips('系统不支持' . $suffix . '格式');
        }
        list($path, $url) = $this->localFileUrl($suffix, $dirtype);
        if (!move_uploaded_file($file->getRealPath(), $path)) {
            tips('文件上传失败');
        }
        $this->oss($path, $url);
        $this->resourceRecord($file->getOriginalName(), $url, $suffix, $file->getSize());
        return ['url' => $url, 'access_url' => $this->domain . $url];
    }
    /**
     * 文件保存
     * @param Stream $stream 二进制文件流
     * @param string $suffix 文件后缀名，如： .png
     * @param string $dirtype
     * @param string $filename
     */
    public function localSave($stream, string $suffix, string $dirtype = FileEnum::TEMP, string $filename = ''): string
    {
        list($path, $url) = $this->localFileUrl($suffix, $dirtype, $filename);
        file_put_contents($path, $stream);
        if ($dirtype != FileEnum::TEMP) {
            $this->oss($path, $url);
        }
        $this->resourceRecord($filename, $url, $suffix, 0);
        return $url;
    }
    /**
     * 本地磁盘路径、磁盘路径对外路径
     * @param string $suffix 文件后缀名，如： .png
     * @param string $dirtype
     * @param string $filename
     */
    public function localFileUrl(string $suffix, $dirtype = '', $filename = ''): array
    {
        $disks = $this->disks['local'];
        if (!$dirtype) {
            $dirtype = FileEnum::IMAGE;
        }
        if (!in_array($dirtype, FileEnum::dirtype())) {
            $dirtype = FileEnum::TEMP;
        }
        $this->dirtype = $dirtype;
        $dir = $disks['root'] . DIRECTORY_SEPARATOR . $dirtype . DIRECTORY_SEPARATOR . date('Ym');
        if (!file_exists($dir)) {
            is_mkdir($dir);
        }

        $filepath = $dir . DIRECTORY_SEPARATOR;
        if ($filename) {
            $filepath .= $filename . '_';
        }
        $filepath .= unique_tag() . $suffix;

        $visibility = app()->getRootPath() . $this->disks['local']['visibility'];
        $url = str_replace($visibility . DIRECTORY_SEPARATOR, '', $filepath);
        return [$filepath, $url];
    }
    /**
     * @param string $path
     * @param string $url
     */
    private function oss(string $path, string $url)
    {
        if ($this->default == 'local') {
            return;
        }
        $driverClass = $this->disks[$this->default]['driver'];
        $client = new $driverClass($this->disks[$this->default]);
        $client->upload($path, $url);
    }
    /**
     * @param string $filename
     * @param string $url
     * @param string $suffix
     * @param integer $size
     */
    private function resourceRecord(string $filename, string $url, string $suffix, int $size = 0): void
    {
        if (empty($filename)) {
            $filename = date('Y-m-d H:i:s') . $suffix;
        }
        $request = request();
        $resource = new ResourceModel();
        $resource->group = $request->port ?? AppEnum::PORT_USER;
        $resource->account_id = $request->uid ?? 0;
        $resource->type = FileEnum::classify($suffix);
        $resource->name = $filename;
        $resource->size = $size ? round($size / FileEnum::MB, 3) . 'MB' : '';
        $resource->path = $url;
        $resource->ip = $request->ip() ?? '';
        $resource->deletable = $this->dirtype == FileEnum::TEMP ? 1 : 0;
        $resource->save();
    }
}
